package com.xuhuan.server.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author huan.xu
 * @Date 2023/6/17 21:07
 * @Description 文件合并工具类
 */
@Slf4j
public class FileCombineUtill {

    private FileCombineUtill() {
    }

    private static int THOUSAND_TWENTY_FOUR = 1024;
    /**
     * 单个文件大小，单位M
     */
    private static int PARTITION_SIZE = 1;

    /**
     * 把指定文件夹内的文件合并为一个文件
     *
     * @param sourcePathList 需要被合并的文件路径集合
     * @param desPath    合并后的文件存放位置
     */
    public static void combineFile(List<String> sourcePathList, String desPath) throws Exception {
        List<String> sortedFilePathList = sortFilesName(sourcePathList);
        File desFile = new File(desPath);
        File desFileParentDir = new File(desFile.getParent());
        if(!desFileParentDir.exists()){
            desFileParentDir.mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(desFile);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        log.info("开始合并文件");
        for (String sortedFilePath : sortedFilePathList) {
            copyFile(bos, sortedFilePath);
        }
        log.info("文件合并完成");

        bos.close();
        fos.close();
    }

    /**
     * 把指定文件夹内的文件合并为一个文件
     *
     * @param sourcePath 需要被合并的文件所在的文件中路径
     * @param desPath    合并后的文件存放位置
     */
    public static void combineFile(String sourcePath, String desPath) throws Exception {
        List<String> sortedFileNames = sortFilesName(sourcePath);
        if (sortedFileNames == null) {
            throw new RuntimeException(sourcePath + "目录下不存在文件");
        }

        File desFile = new File(desPath);
        File desFileParentDir = new File(desFile.getParent());
        if(!desFileParentDir.exists()){
            desFileParentDir.mkdirs();
        }

        FileOutputStream fos = new FileOutputStream(desFile);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        log.info("开始合并文件");
        for (String sortedFileName : sortedFileNames) {
            String filePath = sourcePath + File.separatorChar + sortedFileName;
            copyFile(bos, filePath);

        }
        log.info("文件合并完成");

        bos.close();
        fos.close();
    }

    /**
     * 把目标文件合并到输出流中
     *
     * @param bos 缓冲输出流
     * @param des 目标文件路径
     * @throws IOException
     */
    private static void copyFile(BufferedOutputStream bos, String des) throws Exception {
        FileInputStream fis = new FileInputStream(des);
        BufferedInputStream bis = new BufferedInputStream(fis);

        log.info("------>>>>[{}]开始合并", des);
        byte[] bytes = new byte[THOUSAND_TWENTY_FOUR];
        int length;
        while ((length = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, length);
        }

        bis.close();
        fis.close();
    }

    /**
     * 对指定文件夹内的文件名进行排序 （增序）
     *
     * @param fileDirPath
     * @return
     */
    private static List<String> sortFilesName(String fileDirPath) {
        File dir = new File(fileDirPath);
        File[] fileList = dir.listFiles();
        if (null == fileList || fileList.length == 0) {
            return null;
        }
        Pattern compile = Pattern.compile("^.+_\\d+$");
        return Arrays.stream(fileList)
                .filter(file -> {
                    if (file.isDirectory()) {
                        log.warn("waring:{}不是一个文件", file.getName());
                        return false;
                    }
                    return true;
                })
                .map(File::getName)
                .sorted((fileName1, fileName2) -> {
                    String[] split1 = fileName1.split("_");
                    String[] split2 = fileName2.split("_");
                    return Integer.parseInt(split1[0]) - Integer.parseInt(split2[0]);
                }).collect(Collectors.toList());
    }

    /**
     * 对指定文件夹内的文件名进行排序 （增序）
     *
     * @param filePathList
     * @return
     */
    private static List<String> sortFilesName(List<String> filePathList) {
        Pattern compile = Pattern.compile("^.+_\\d+$");
        return filePathList.stream()
                .sorted((filePath1,filePath2)->{
                    return Integer.parseInt(getFileNameProfix(filePath1)) - Integer.parseInt(getFileNameProfix(filePath2));
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取文件名前缀
     * @param filePath
     * @return
     */
    public static String getFileNameProfix(String filePath){
        int index = filePath.lastIndexOf(File.separator);
        String fileName = filePath.substring(index + 1, filePath.length());
        return fileName.split("_")[0];
    }

    public static void main(String[] args) throws Exception {
        String targetFilePath = "C:\\Users\\Administrator\\Desktop\\file-split\\aims-client2.zip";

        List<String> sourcePathList =new ArrayList<>();
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\0_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\10_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\11_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\12_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\13_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\14_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\15_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\16_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\17_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\18_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\19_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\1_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\20_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\21_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\22_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\23_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\24_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\25_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\26_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\27_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\28_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\29_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\2_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\30_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\31_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\32_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\33_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\34_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\35_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\36_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\3_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\4_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\5_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\6_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\7_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\8_cba22921f0164c05");
        sourcePathList.add("C:\\Users\\Administrator\\Desktop\\file-split\\test\\cba22921f0164c05\\9_cba22921f0164c05");

        FileCombineUtill.combineFile(sourcePathList, targetFilePath);
    }
}
